home *** CD-ROM | disk | FTP | other *** search
/ Aminet 46 / Aminet 46 (2001)(GTI - Schatztruhe)[!][Dec 2001].iso / Aminet / text / edit / edt10src.lha / txt / Threads.mod < prev    next >
Text File  |  1995-03-19  |  5KB  |  209 lines

  1. (*
  2.   .name       Threads
  3.   .task       multithreading
  4.   .release    1.0
  5.   .language   Oberon-2
  6.   .translator Amiga Oberon 3.11
  7.   .system     AmigaOS 2.04/2.1/3.0
  8.   .author     J. Barheine
  9.   .address    Hochgrevestr. 3
  10.   .copyright  (c) 1995 by J. Barheine
  11. *)
  12.  
  13. (* .info: 06/09/93, 15:35:27, version 00 *)
  14.  
  15. MODULE Threads;
  16.  
  17. IMPORT
  18.   SYS:= SYSTEM,
  19.  
  20.   Dos,
  21.   Exec,
  22.   K:= Kernel,
  23.   OberonLib;
  24.  
  25. TYPE
  26.   Waiting = UNTRACED POINTER TO WaitingDesc;
  27.   Thread* = UNTRACED POINTER TO ThreadDesc;
  28.  
  29.   ThreadProc* = PROCEDURE (data: K.ANY): K.ANY;
  30.  
  31.   ThreadDesc* = RECORD (K.ANYDesc)
  32.     next: Thread;                 (* link *)
  33.     dosProcess: Dos.ProcessPtr;   (* AmigaOS-Thread *)
  34.     done: BOOLEAN;                (* terminated? *)
  35.     data: K.ANY;                  (* passed data *)
  36.     result: K.ANY;                (* result of this thread *)
  37.     taskTrapData: OberonLib.TaskTrapData;
  38.     proc: ThreadProc;             (* The main thread procedure *)
  39.     waiting: Waiting;             (* thread waiting for our termination *)
  40.   END;
  41.  
  42.   WaitingDesc = RECORD (K.ANYDesc)
  43.     next: Waiting;                (* link *)
  44.     task: Exec.TaskPtr;           (* waiting task *)
  45.   END;
  46.  
  47. VAR
  48.   threadList: Thread;
  49.   startThreadProc: Thread;
  50.   sema: Exec.SignalSemaphore;
  51.   wakeUpSig: INTEGER;
  52.   defStackSize: LONGINT;
  53.   dataIndex: INTEGER;  (* taskTrapData.user[] - index *)
  54.  
  55. PROCEDURE ChildHaltProc;
  56.  
  57. VAR
  58.   p, q: Thread;
  59.  
  60. CONST
  61.   rts = 4E75H;
  62.  
  63. BEGIN
  64.   p:= SYS.VAL(Thread, OberonLib.execBase.thisTask.trapData.user[dataIndex]);
  65.   Exec.ObtainSemaphore(sema);
  66.   Exec.Forbid;
  67.   p.done:= TRUE;
  68.   WHILE p.waiting # NIL DO
  69.     Exec.Signal(p.waiting.task, LONGSET{wakeUpSig});
  70.     p.waiting:= p.waiting.next;
  71.   END;
  72.   IF p = threadList THEN
  73.     threadList:= p.next
  74.   ELSE
  75.     q:= threadList;
  76.     WHILE q.next # p DO q:= q.next END;
  77.     q.next:= p.next;
  78.   END;
  79.   Exec.ReleaseSemaphore(sema);
  80.   SYS.SETREG(15, OberonLib.execBase.thisTask.trapData.oldSP);
  81.   SYS.INLINE(rts);
  82. END ChildHaltProc;
  83.  
  84. PROCEDURE Call(p: Thread);
  85.  
  86. BEGIN
  87.   p.result:= p.proc(p.data);
  88.   ChildHaltProc;
  89. END Call;
  90.  
  91. (* $StackChk- *)
  92.  
  93. PROCEDURE StartProc;
  94.  
  95. BEGIN
  96.   startThreadProc:= SYS.VAL(Thread, OberonLib.execBase.thisTask.trapData.user[dataIndex]);
  97.   Call(startThreadProc);
  98. END StartProc;
  99.  
  100.  
  101. PROCEDURE StartThread;  (* sets A5 and trapData.oldSP *)
  102.  
  103. BEGIN
  104.   OberonLib.SetA5;
  105.   (* $IF SmallData *)
  106.   OberonLib.execBase.thisTask.trapData.oldSP:= SYS.REG(15);
  107.   (* $ELSE *)
  108.   OberonLib.execBase.thisTask.trapData.oldSP:= SYS.VAL(LONGINT, SYS.REG(15))-4;
  109.   (* $END *)
  110.   StartProc;
  111. END StartThread;
  112.  
  113. (* $StackChk= *)
  114.  
  115. (* run proc in a seperate thread *)
  116. PROCEDURE RunInThread* (proc: ThreadProc; data: K.ANY; priority: SHORTINT): Thread;
  117.  
  118. VAR
  119.   p: Thread;
  120.   msg: Dos.ProcessId;
  121.  
  122. BEGIN
  123.   NEW(p);
  124.   p.taskTrapData:= OberonLib.execBase.thisTask.trapData^;
  125.   p.taskTrapData.haltProc:= ChildHaltProc;
  126.   p.taskTrapData.user[dataIndex]:= SYS.VAL(SYS.ADDRESS, p);
  127.   p.data:= data;
  128.   p.proc:= proc;
  129.   p.done:= FALSE;
  130.  
  131.   Exec.ObtainSemaphore(sema);
  132.   Exec.Forbid;
  133.   p.dosProcess:= Dos.CreateNewProcTags(Dos.npEntry, SYS.VAL(SYS.ADDRESS, StartThread),
  134.                                       Dos.npStackSize, defStackSize,
  135.                                       Dos.npPriority , priority);
  136.   IF p.dosProcess # NIL THEN
  137.     p.dosProcess.task.trapData:= SYS.ADR(p.taskTrapData);
  138.     p.dosProcess.task.trapCode:= Exec.exec.thisTask.trapCode;
  139.     p.next:= threadList;
  140.     threadList:= p;
  141.   ELSE
  142.     p:= NIL;
  143.   END;
  144.   Exec.Permit;
  145.   Exec.ReleaseSemaphore(sema);
  146.  
  147.   RETURN p;
  148. END RunInThread;
  149.  
  150.  
  151. (* wait for p to terminate *)
  152. PROCEDURE (p: Thread) Wait* (): K.ANY;
  153.  
  154. VAR
  155.   wait: Waiting;
  156.  
  157. BEGIN
  158.   Exec.ObtainSemaphore(sema);
  159.   IF ~p.done THEN
  160.     NEW(wait);
  161.     wait.task:= Exec.exec.thisTask;
  162.     wait.next:= p.waiting;
  163.     p.waiting:= wait;
  164.     Exec.ReleaseSemaphore(sema);
  165.     REPEAT UNTIL p.done OR (wakeUpSig IN Exec.Wait(LONGSET{wakeUpSig}));
  166.   ELSE
  167.     Exec.ReleaseSemaphore(sema);
  168.   END;
  169.   RETURN p.result;
  170. END Wait;
  171.  
  172. (* check if p is still running *)
  173. PROCEDURE (p: Thread) IsRunning* (): BOOLEAN;
  174.  
  175. BEGIN
  176.   RETURN ~p.done
  177. END IsRunning;
  178.  
  179. (* wait for all threads to terminate *)
  180. PROCEDURE WaitForAllThreads* ;
  181.  
  182. VAR
  183.   p: Thread;
  184.  
  185. BEGIN
  186.   LOOP
  187.     Exec.ObtainSemaphore(sema);
  188.     p:= threadList;
  189.     Exec.ReleaseSemaphore(sema);
  190.     IF p = NIL THEN EXIT END;
  191.     IF p.Wait()=NIL THEN END;
  192.   END;
  193. END WaitForAllThreads;
  194.  
  195. BEGIN
  196.   Exec.InitSemaphore(sema);
  197.   threadList:= NIL;
  198.   defStackSize:= OberonLib.OldSP.stackSize;
  199.   wakeUpSig:= Exec.AllocSignal(-1);
  200.   dataIndex:= OberonLib.AllocUser();
  201.   IF (wakeUpSig < 0) OR (dataIndex < 0) THEN HALT(20) END;
  202.  
  203. CLOSE
  204.   WaitForAllThreads;
  205.  
  206.   IF wakeUpSig >= 0 THEN Exec.FreeSignal(wakeUpSig) END;
  207.   IF dataIndex >= 0 THEN OberonLib.FreeUser(dataIndex) END;
  208. END Threads.
  209.